-- 构造 commonlib 对象
local commonlib = _G.commonlib or {};
_G.commonlib = commonlib;

-- 备份路径
commonlib.__is_dev_env__ = LuaGui.IsDevEnv();
commonlib.__storage_directory__ = LuaGui.GetStorageDirectory();
commonlib.__virtual_directory__ = LuaGui.GetVirtualDirectory();
commonlib.__package_directory__ = LuaGui.GetPackageDirectory();
commonlib.__asset_directory__ = LuaGui.GetAssetDirectory();
commonlib.__script_directory__ = LuaGui.GetScriptDirectory();
commonlib.__path_alias_map__ = {
    ["@storage"] = commonlib.__storage_directory__,
    ["@package"] = commonlib.__package_directory__,
    ["@script"] = commonlib.__script_directory__,
}; 

-- 设置包目录PATH
package.path =  LuaGui.FileSystem.FormatPath(commonlib.__package_directory__  .. "/?/init.lua;") .. package.path;
package.path =  LuaGui.FileSystem.FormatPath(commonlib.__package_directory__  .. "/?.lua;") .. package.path;

-- log
commonlib.__log_debug__ = LuaGui.Log.Debug;
commonlib.__log_info__ = LuaGui.Log.Info;
commonlib.__log_warn__ = LuaGui.Log.Warn;
commonlib.__log_error__ = LuaGui.Log.Error;

-- commonlib.__log_debug__("=================commonlib init=================");

-- 打印堆栈
function commonlib.__debug_traceback__(begin_depth, end_depth)
    commonlib.__log_debug__("=================debug_traceback begin=================");
    begin_depth = begin_depth or 2;
    end_depth = end_depth or 50;
    local last_functio_name = "";
    for i = 1, end_depth do
	    local info = debug.getinfo(i, "nSl");
        local logmsg = "";
        if (not info or info == "") then break end
        if (info.what == "C") then
            logmsg = "C function"; 
        else
            filepath = string.sub(info.source, 1, string.find(info.source, "\n", 1, true));
            filepath = string.gsub(filepath, "%s*$", "");
            filepath = string.gsub(filepath, "^%s*", "");
            logmsg = string.format("%s:%d %s", filepath, info.currentline, last_functio_name);
            last_functio_name = info.name or "";
        end
        if (i >= begin_depth) then commonlib.__log_debug__(logmsg) end 
    end
    commonlib.__log_debug__("=================debug_traceback end=================");
end

-- 保护执行
function commonlib.__xpcall__(func, ...)
    return xpcall(func, function(errmsg)
        commonlib.__log_error__(errmsg);
        commonlib.__debug_traceback__(3);
    end, ...)
end

-- 保护执行回调
function commonlib.__xpcall_callback__(func)
    return function(...)
        return commonlib.__xpcall__(func, ...);
    end
end

-- 核心函数
function commonlib.exit(errmsg) 
    if (errmsg ~= nil) then
        commonlib.__log_error__(errmsg);
        commonlib.__debug_traceback__(3);
    end
    LuaGui.Exit();
end


function commonlib.GetScriptTextByFilePath(filepath)
    return LuaGui.GetScriptTextByFilePath(filepath);
end

function commonlib.GetAssetTextByFilePath(filepath)
    return LuaGui.FileSystem.LoadAsset(filepath);
end

function commonlib.GetScriptDirectory()
    return commonlib.__script_directory__;
end

function commonlib.GetDirectory(filepath)
    return filepath and string.gsub(filepath, "([^\\/]*)$", "");
end

function commonlib.GetFileName(filepath)
    return filepath and string.match(filepath, "([^\\/]*)$");
end

function commonlib.FormatPath(path, platform)
    return LuaGui.FileSystem.FormatPath(path);
end

function commonlib.SetPathAlias(alias, path)
    commonlib.__path_alias_map__[string.lower(alias)] = path or "";
end

-- 格式化文件名
function commonlib.GetFullPath(filepath)
    local path = string.gsub(filepath or "", "(@[%w_]*)", function(alias)
        local path = commonlib.__path_alias_map__[string.lower(alias)];
        if (type(path) == "string") then return path end
        if (type(path) == "function") then return path() end
        return "";
    end)
    return commonlib.FormatPath(path);
end

function commonlib.IsAssetFilePath(filepath)
    return string.sub(filepath, 1, string.len(commonlib.__asset_directory__)) == commonlib.__asset_directory__;
end

function commonlib.IsScriptFilePath(filepath)
    return string.sub(filepath, 1, string.len(commonlib.__script_directory__)) == commonlib.__script_directory__;
end

function commonlib.IsAbsolutePath(path)
    return LuaGui.FileSystem.IsAbsolutePath(path);
end

function commonlib.GetAbsolutePath(path)
    if (commonlib.IsAbsolutePath(path)) then
        return commonlib.FormatPath(path);
    end
    return LuaGui.FileSystem.GetAbsolutePath(path);
end

commonlib.__commonlib_directory__ = commonlib.FormatPath(commonlib.__script_directory__ .. "/commonlib");
commonlib.__commonlib_filename__ = commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/init.lua");

commonlib.__modules__ = {};
function commonlib.export(module, current_filename)
    module = module or {};
    
    local full_path = current_filename;
    if (commonlib.IsScriptFilePath(full_path) or commonlib.IsAbsolutePath(full_path)) then
        full_path = commonlib.FormatPath(full_path);
    else     
        return module;
    end 
    
    commonlib.__modules__[full_path] = commonlib.__modules__[full_path] or {__loaded__ = false};
    commonlib.__modules__[full_path].__module__ = module;
    return module;
end

-- 加载模块
function commonlib.import(filepath, current_filename)
    local full_path = commonlib.GetFullPath(filepath);

    if (commonlib.IsScriptFilePath(full_path) or commonlib.IsAbsolutePath(full_path)) then
        full_path = commonlib.FormatPath(full_path);
    else     
        full_path = commonlib.FormatPath(commonlib.GetDirectory(current_filename) .. "/" .. full_path)
    end 

    --commonlib.__log_debug__(full_path)

    commonlib.__modules__[full_path] = commonlib.__modules__[full_path] or {};
    local __module__ = commonlib.__modules__[full_path];
    if (__module__.__loaded__) then return __module__.__module__ end 
    
    __module__.__filename__ = full_path;
    __module__.__directory__ = commonlib.GetDirectory(full_path);
    __module__.__loaded__ = true;
    __module__.import = function(filepath) 
        return commonlib.import(filepath, __module__.__filename__);
    end
    __module__.export = function(module)
        return commonlib.export(module, __module__.__filename__);
    end
    setmetatable(__module__, {__index = _G});

    local func, errmsg = commonlib.loadscript(full_path, "bt", __module__);
    if (not func) then
        commonlib.__log_warn__(errmsg);
        commonlib.__log_warn__("ERROR: loadfile failed:" .. full_path);
        return nil;
    end

    -- local ok, result = pcall(func);
    local ok, result = commonlib.__xpcall__(func);
    if (not ok) then
        commonlib.__log_warn__("ERROR: import failed:" .. filepath);
    else
        --commonlib.__log_debug__("Load Module:" .. full_path .. " value:" .. tostring(result == nil));
        if (__module__.__module__ == nil) then
            __module__.__module__ = result;
        end
    end

    commonlib.__modules__[full_path] = __module__;
    return commonlib.__modules__[full_path].__module__;
end

function commonlib.loadscript(filepath, mode, module_env)
    mode = mode or "bt";
    local filetext = commonlib.GetScriptTextByFilePath(filepath);
    return load(filetext, filepath, mode, module_env);
end

function commonlib.nullfunc() 
end 

function commonlib.loadstring(chunk, env, chunkname, mode)
    if (type(chunk) ~= "string") then return nil, false end 

    local func, errmsg = _G.load(chunk, chunkname or "dostring", mode or "bt", env or _G);

    if (not func) then
        commonlib.__log_warn__("ERROR: loadstring->load", chunk);
    else
        return func, true;
    end 

    return nil, false;
end

function commonlib.dostring(chunk, env, chunkname, mode)
    if (type(chunk) ~= "string") then return nil, false end 

    local func, errmsg = _G.load(chunk, chunkname or "dostring", mode or "bt", env);

    if (not func) then
        commonlib.__log_warn__("ERROR: dostring->load failed", chunk);
    else
        local ok, result = xpcall(func, function(errmsg)
            print(commonlib.__debug_traceback__());
            return errmsg;
        end);
        if (not ok) then
            commonlib.__log_error__("ERROR: dostring->pcall failed", result);
        else 
            return result, true;
        end
    end

    return nil, false;
end

-- table
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/table.lua"));
-- utf8 string
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/string.lua"));
-- log
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/log.lua"));
-- commonlib
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/commonlib.lua"));
-- system
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/system.lua"));
-- filesystem
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/filesystem.lua"));
-- util
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/util.lua"));
-- EventEmitter 
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/EventEmitter.lua"));
-- ToolBase
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/ToolBase.lua"));
-- Timer
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/Timer.lua"));
-- external libs
commonlib.import(commonlib.FormatPath(commonlib.__commonlib_directory__ .. "/luarocks/init.lua"));

return commonlib;


